package com.wanna.common.doc.document.impl;

import com.wanna.common.doc.document.ApiDoc;
import com.wanna.common.doc.entity.ApiInfo;
import com.wanna.common.doc.entity.MethodInfo;
import com.wanna.common.doc.entity.ParamInfo;
import com.wanna.common.doc.util.LineUtil;
import com.wanna.common.io.FileUtil;
import com.wanna.common.lang.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

/**
 * 生产  markdown 形式的接口文档
 *
 * @author wanna
 * @since 2018-11-25
 */
public class MarkdownDoc implements ApiDoc {

    private static final Logger LOG = LoggerFactory.getLogger(MarkdownDoc.class);

    private static final String METHOD_LINK = "- [{{method}}](#{{description}})";

    private static final String PARAM_LINK = "    - [参数说明](#{{param}})";

    private static final String RETURN_LINK = "    - [返回值说明](#{{param}})";

    private static final String FILE_SUFFIX = ".md";

    @Override
    public boolean generateDoc(List<ApiInfo> interfaces, String savePath) throws Exception {
        for (ApiInfo apiInfo : interfaces) {
            List<String> lines = new LinkedList<>();
            String name = apiInfo.getName();
            String file = StringUtil.remove(savePath, "/") + "/" + name + FILE_SUFFIX;
            String description = apiInfo.getDescription();
            List<MethodInfo> methods = apiInfo.getMethods();

            // 添加文件头
            putCenter(lines, name, description);
            // 添加方法瞄点
            putMethodsLink(lines, methods);
            // 添加方法参数返回值信息
            putMethodsInfo(lines, methods);

            FileUtil.writeLines(new File(file), lines);
            LOG.info("markdown {} 已生成,完整路径为 {} ....", name, file);
        }

        return false;
    }

    /**
     * 添加 居中的头
     *
     * @param lines       lines
     * @param name        name
     * @param description description
     */
    private void putCenter(List<String> lines, String name, String description) {
        String center = StringUtil.isEmpty(description) ? name : description;
        lines.add("<center>" + center + "</center>");
        lines.add("");
    }

    /**
     * 添加方法参数返回信息
     *
     * @param lines   lines
     * @param methods method
     */
    private void putMethodsInfo(List<String> lines, List<MethodInfo> methods) {
        methods.forEach(method -> {
            putMethodBaseInfo(lines, method);

            putMethodParamInfo(lines, method);

            putMethodReturnValue(lines, method);

            putMethodBlankLine(lines);
        });
    }

    /**
     * 方法空行
     *
     * @param lines lines
     */
    private void putMethodBlankLine(List<String> lines) {
        lines.add("<hr>");
        lines.add("");
    }

    /**
     * 添加方法返回值
     *
     * @param lines  lines
     * @param method method
     */
    private void putMethodReturnValue(List<String> lines, MethodInfo method) {
        lines.add("### 返回值说明");
        lines.add("```");
        lines.add(method.getReturnSample());
        lines.add("```");
    }

    /**
     * 添加方法参数
     *
     * @param lines  lines
     * @param method method
     */
    private void putMethodParamInfo(List<String> lines, MethodInfo method) {
        lines.add("### 参数说明");
        lines.add("```");
        List<ParamInfo> params = method.getParams();
        for (ParamInfo info : params) {
            String line = fillParamLine(info);
            lines.add(line);

            if (StringUtil.isNotEmpty(info.getJsonSample())) {
                lines.add(info.getJsonSample());
            }
        }
        lines.add("```");
    }

    /**
     * 组装 参数 行
     *
     * @param info paramInfo
     * @return
     */
    private String fillParamLine(ParamInfo info) {
        String str = info.isRequired() ? "是" : "否";
        String requiredStr = "是否必填: " + str;
        return LineUtil.fillBlank("参数: " + info.getName(), 20) + LineUtil.fillBlank(requiredStr, 15)
                + LineUtil.fillBlank("类型: " + info.getType(), 30) + LineUtil.fillBlank("描述: " + info.getDescription(), 20);
    }

    /**
     * 添加方法基本信息
     *
     * @param lines  lines
     * @param method method
     */
    private void putMethodBaseInfo(List<String> lines, MethodInfo method) {
        lines.add("## " + method.getName());
        lines.add("### 基本信息");
        lines.add("```");
        String path = "接口路径:/" + StringUtil.removeStart(method.getPath(), "/");
        String request = "请求方式:" + " " + method.getRequestType();
        lines.add(LineUtil.fillBlank(path, 50) + LineUtil.fillBlank(request, 50));
        lines.add("```");
    }

    /**
     * 添加方法瞄点
     *
     * @param lines   lines
     * @param methods method
     */
    private void putMethodsLink(List<String> lines, List<MethodInfo> methods) {
        lines.add("<!-- TOC -->");
        methods.forEach(method -> methodLink(lines, method));
        lines.add("<!-- /TOC -->");
        lines.add("");
    }

    /**
     * 添加方法瞄点
     *
     * @param lines  lines
     * @param method method
     */
    private void methodLink(List<String> lines, MethodInfo method) {
        String description = method.getDescription();

        String name = method.getName();
        description = StringUtil.isEmpty(description) ? name : description;

        lines.add(METHOD_LINK.replace("{{method}}", name).replace("{{description}}", description));
        lines.add(PARAM_LINK.replace("{{param}}", name));
        lines.add(RETURN_LINK.replace("{{param}}", name));
    }
}
